package com.alogic.pipeline;

import com.alogic.load.Loadable;
import com.alogic.uid.IdGenerator;
import com.anysoft.util.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Stage接口
 *
 * @since 1.6.13.35 [20210218 duanyy] <br>
 *
 * @version 1.6.15.3 [20211112 duanyy] <br>
 * - 优化pipeline的tolerable机制 <br>
 */
public interface PipelineStage extends Loadable {
    public void prepare(String jobId,Properties ctx,PipelineListener listener);
    public void run(String jobId, Properties ctx, PipelineListener listener);
    public boolean isFaultTolerable();
    /**
     * 虚基类
     */
    public static abstract class Abstract extends Loadable.Abstract
            implements PipelineStage, XMLConfigurable, Configurable,PipelineListener{
        protected Logger LOG = LoggerFactory.getLogger(Pipeline.class);
        protected List<Pair<String,String>> pairs = new ArrayList<Pair<String,String>>();
        protected String $prefix = "stage.";
        protected PipelineListener listener = null;
        protected String id = "default";
        protected boolean faultTolerable = false;
        /**
         * 用来生成id
         */
        protected IdGenerator uid = null;

        public boolean isNull(){
            return StringUtils.isEmpty(id);
        }

        @Override
        public String getId(){
            return id;
        }


        @Override
        public boolean isFaultTolerable(){
            return false;
        }

        @Override
        public void configure(Properties p) {
            $prefix = PropertiesConstants.getRaw(p,"prefix",$prefix);
            id = PropertiesConstants.getString(p,"id",id);
            faultTolerable = PropertiesConstants.getBoolean(p,"tolerable",faultTolerable);
        }

        @Override
        public void configure(Element e, Properties p) {
            XmlElementProperties props = new XmlElementProperties(e,p);
            configure(props);
            loadPairs(e,p);
        }

        protected void loadPairs(Element e, Properties p){
            NamedNodeMap attrs = e.getAttributes();
            for (int i = 0 ; i < attrs.getLength() ; i ++){
                Node node = attrs.item(i);
                String key = node.getNodeName();
                String value = node.getNodeValue();
                if (StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value)){
                    pairs.add(new Pair.Default<String,String>(key,value));
                }
            }
        }

        @Override
        public boolean isCanceled(String jobId) {
            return listener == null ? false:listener.isCanceled(jobId);
        }

        @Override
        public String newId() {
            return listener == null ? uid.nextId():listener.newId();
        }

        @Override
        public void onCreate(String jobId, Properties ctx) {
            if (listener != null){
                listener.onCreate(jobId,ctx);
            }
        }

        @Override
        public void onFinish(String jobId, Properties ctx) {
            if (listener != null){
                listener.onFinish(jobId,ctx);
            }
        }

        @Override
        public void onCreate(String jobId, String stageId, Properties ctx) {
            if (listener != null){
                listener.onCreate(jobId,stageId,ctx);
            }
        }

        @Override
        public void onFinish(String jobId, String stageId, Properties ctx) {
            if (listener != null){
                listener.onFinish(jobId,stageId,ctx);
            }
        }

        @Override
        public void onCreate(String jobId, String stageId, String stepId, Properties ctx) {
            if (listener != null){
                listener.onCreate(jobId,stageId,stepId,ctx);
            }
        }

        @Override
        public void onFinish(String jobId, String stageId, String stepId, Properties ctx) {
            if (listener != null){
                listener.onFinish(jobId,stageId,stepId,ctx);
            }
        }

        @Override
        public void onStart(String jobId, Properties ctx) {
            if (listener != null){
                listener.onStart(jobId,ctx);
            }
        }

        @Override
        public void onStart(String jobId, String stageId, Properties ctx) {
            if (listener != null){
                listener.onStart(jobId,stageId,ctx);
            }
        }

        @Override
        public void onStart(String jobId, String stageId, String stepId, Properties ctx) {
            if (listener != null){
                listener.onStart(jobId,stageId,stepId,ctx);
            }
        }

        @Override
        public void report(Element xml) {
            if (xml != null){
                XmlTools.setString(xml,"module",getClass().getName());
            }
        }

        @Override
        public void report(Map<String, Object> json) {
            if (json != null){
                JsonTools.setString(json,"module",getClass().getName());
            }
        }
    }

    /**
     * Base
     */
    public static abstract class Base extends Abstract{
        @Override
        public void prepare(String jobId, Properties ctx, PipelineListener listener) {
            this.listener = listener;
            String prefix = PropertiesConstants.transform(ctx,$prefix,"stage.");
            for (Pair<String,String> pair:pairs){
                ctx.SetValue(prefix + pair.key(),pair.value());
            }
        }
    }
}
